<template>
	<div class="vue3-cron-div">
		<div class="flex">
			<el-tooltip>
				<el-select v-model="state.cron" class="flex-1" allow-create filterable @change="selectSimple">
					<el-option v-for="item in CronSimple" :key="item.key" :value="item.key" :label="item.label"> </el-option>
				</el-select>
				<template #content>
					{{ formatCron(state.cron) }}
				</template>
			</el-tooltip>
			<el-link type="primary" class="ml-2" @click="() => (state.advanced = true)">高级</el-link>
			<DialogBox title="配置定时器" class="cron-dialog" width="650px" v-model:visible="state.advanced" @confirm="change">
				<div class="mb-4">
					<el-radio v-model="state.configType" label="simple">可视化配置</el-radio>
					<el-radio v-model="state.configType" label="customer">自定义配置</el-radio>
				</div>
				<template v-if="state.configType == 'simple'">
					<el-tabs type="border-card" v-model="state.currTab">
						<!-- 秒 -->
						<el-tab-pane name="second">
							<template #label>
								<span><i class="el-icon-date"></i> {{ Language.Seconds.name }}</span>
							</template>
							<div class="tabBody myScroller" :style="{ 'max-height': maxHeight }">
								<!-- 每一秒 -->
								<el-row>
									<el-radio v-model="state.second.cronEvery" label="1">{{ Language.Seconds.every }}</el-radio>
								</el-row>
								<!-- 具体秒 -->
								<el-row>
									<el-radio class="long" v-model="state.second.cronEvery" label="3">
										{{ Language.Seconds.specific }}
										<el-select
											multiple
											v-model="state.second.specificSpecific"
											style="width: 350px"
											@change="state.second.cronEvery = '3'"
										>
											<el-option v-for="(val, index) in 60" :key="index" :value="val - 1">{{ val - 1 }}</el-option>
										</el-select>
									</el-radio>
								</el-row>
								<!-- 间隔 -->
								<el-row>
									<el-radio v-model="state.second.cronEvery" label="2"
										>{{ Language.Seconds.interval[0] }}
										<el-input-number v-model="state.second.incrementIncrement" :min="1" :max="60"></el-input-number>
										{{ Language.Seconds.interval[1] || "" }}
										<el-input-number v-model="state.second.incrementStart" :min="0" :max="59"></el-input-number>
										{{ Language.Seconds.interval[2] || "" }}
									</el-radio>
								</el-row>
								<!-- 周期 -->
								<el-row>
									<el-radio v-model="state.second.cronEvery" label="4"
										>{{ Language.Seconds.cycle[0] }}
										<el-input-number v-model="state.second.rangeStart" :min="1" :max="60"></el-input-number>
										{{ Language.Seconds.cycle[1] || "" }}
										<el-input-number v-model="state.second.rangeEnd" :min="0" :max="59" style="width: 214px"></el-input-number>
										{{ Language.Seconds.cycle[2] || "" }}
									</el-radio>
								</el-row>
							</div>
						</el-tab-pane>
						<!-- 分 -->
						<el-tab-pane name="minute">
							<template #label>
								<span><i class="el-icon-date"></i> {{ Language.Minutes.name }}</span>
							</template>
							<div class="tabBody myScroller" :style="{ 'max-height': maxHeight }">
								<!-- 每分钟 -->
								<el-row>
									<el-radio v-model="state.minute.cronEvery" label="1">{{ Language.Minutes.every }}</el-radio>
								</el-row>
								<!-- 具体分钟 -->
								<el-row>
									<el-radio class="long" v-model="state.minute.cronEvery" label="3"
										>{{ Language.Minutes.specific }}
										<el-select multiple v-model="state.minute.specificSpecific" @change="state.minute.cronEvery = '3'">
											<el-option v-for="(val, index) in 60" :key="index" :value="val - 1">{{ val - 1 }}</el-option>
										</el-select>
									</el-radio>
								</el-row>
								<!-- 间隔 -->
								<el-row>
									<el-radio v-model="state.minute.cronEvery" label="2"
										>{{ Language.Minutes.interval[0] }}
										<el-input-number v-model="state.minute.incrementIncrement" :min="1" :max="60"></el-input-number>
										{{ Language.Minutes.interval[1] }}
										<el-input-number v-model="state.minute.incrementStart" :min="0" :max="59"></el-input-number>
										{{ Language.Minutes.interval[2] || "" }}
									</el-radio>
								</el-row>
								<!-- 周期 -->
								<el-row>
									<el-radio v-model="state.minute.cronEvery" label="4"
										>{{ Language.Minutes.cycle[0] }}
										<el-input-number v-model="state.minute.rangeStart" :min="1" :max="60"></el-input-number>
										{{ Language.Minutes.cycle[1] }}
										<el-input-number v-model="state.minute.rangeEnd" :min="0" :max="59" style="width: 214px"></el-input-number>
										{{ Language.Minutes.cycle[2] }}
									</el-radio>
								</el-row>
							</div>
						</el-tab-pane>
						<!-- 时 -->
						<el-tab-pane name="hour">
							<template #label>
								<span><i class="el-icon-date"></i> {{ Language.Hours.name }}</span>
							</template>
							<div class="tabBody myScroller" :style="{ maxHeight: maxHeight || 'auto' }">
								<el-row>
									<el-radio v-model="state.hour.cronEvery" label="1">{{ Language.Hours.every }}</el-radio>
								</el-row>
								<el-row>
									<el-radio class="long" v-model="state.hour.cronEvery" label="3"
										>{{ Language.Hours.specific }}
										<el-select multiple v-model="state.hour.specificSpecific" @change="state.hour.cronEvery = '3'">
											<el-option v-for="(val, index) in 24" :key="index" :value="val - 1">{{ val - 1 }}</el-option>
										</el-select>
									</el-radio>
								</el-row>
								<el-row>
									<el-radio v-model="state.hour.cronEvery" label="2"
										>{{ Language.Hours.interval[0] }}
										<el-input-number v-model="state.hour.incrementIncrement" :min="0" :max="23"></el-input-number>
										{{ Language.Hours.interval[1] }}
										<el-input-number
											v-model="state.hour.incrementStart"
											:min="0"
											:max="23"
											style="width: 164px"
										></el-input-number>
										{{ Language.Hours.interval[2] }}
									</el-radio>
								</el-row>
								<el-row>
									<el-radio v-model="state.hour.cronEvery" label="4"
										>{{ Language.Hours.cycle[0] }}
										<el-input-number v-model="state.hour.rangeStart" :min="0" :max="23"></el-input-number>
										{{ Language.Hours.cycle[1] }}
										<el-input-number v-model="state.hour.rangeEnd" :min="0" :max="23" style="width: 212px"></el-input-number>
										{{ Language.Hours.cycle[2] }}
									</el-radio>
								</el-row>
							</div>
						</el-tab-pane>
						<!-- 天 -->
						<el-tab-pane name="day">
							<template #label>
								<span><i class="el-icon-date"></i> {{ Language.Day.name }}</span>
							</template>
							<div class="tabBody myScroller" :style="{ 'max-height': maxHeight }">
								<el-row>
									<el-radio v-model="state.day.cronEvery" label="1">{{ Language.Day.every }}</el-radio>
								</el-row>
								<el-row>
									<el-radio class="long" v-model="state.day.cronEvery" label="5">
										{{ Language.Day.specificDay }}
										<el-select
											multiple
											v-model="state.day.specificSpecific"
											style="width: 348px"
											@change="state.day.cronEvery = '5'"
										>
											<el-option v-for="(val, index) in 31" :key="index" :value="val">{{ val }}</el-option>
										</el-select>
									</el-radio>
								</el-row>
								<el-row>
									<el-radio class="long" v-model="state.day.cronEvery" label="4"
										>{{ Language.Day.specificWeek }}
										<el-select multiple v-model="state.week.specificSpecific" @change="state.day.cronEvery = '4'">
											<el-option
												v-for="(val, index) in 7"
												:key="index"
												:label="Language.Week[val - 1]"
												:value="['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'][val - 1]"
											></el-option>
										</el-select>
									</el-radio>
								</el-row>
								<el-row>
									<el-radio v-model="state.day.cronEvery" label="2"
										>{{ Language.Day.intervalWeek[0] }}
										<el-input-number v-model="state.week.incrementIncrement" :min="1" :max="7"></el-input-number>
										{{ Language.Day.intervalWeek[1] }}
										<el-select v-model="state.week.incrementStart" style="width: 178px">
											<el-option v-for="(val, index) in 7" :key="index" :label="Language.Week[val - 1]" :value="val"></el-option>
										</el-select>
										{{ Language.Day.intervalWeek[2] }}
									</el-radio>
								</el-row>
								<el-row>
									<el-radio v-model="state.day.cronEvery" label="3"
										>{{ Language.Day.intervalDay[0] }}
										<el-input-number v-model="state.day.incrementIncrement" :min="1" :max="31"></el-input-number>
										{{ Language.Day.intervalDay[1] }}
										<el-input-number v-model="state.day.incrementStart" :min="1" :max="31"></el-input-number>
										{{ Language.Day.intervalDay[2] }}
									</el-radio>
								</el-row>

								<el-row>
									<el-radio v-model="state.day.cronEvery" label="6">{{ Language.Day.lastDay }}</el-radio>
								</el-row>
								<el-row>
									<el-radio v-model="state.day.cronEvery" label="7">{{ Language.Day.lastWeekday }}</el-radio>
								</el-row>
								<el-row>
									<el-radio v-model="state.day.cronEvery" label="8"
										>{{ Language.Day.lastWeek[0] }}
										<el-select v-model="state.day.cronLastSpecificDomDay" style="width: 330px">
											<el-option v-for="(val, index) in 7" :key="index" :label="Language.Week[val - 1]" :value="val"></el-option>
										</el-select>
										{{ Language.Day.lastWeek[1] || "" }}
									</el-radio>
								</el-row>
								<!-- <el-row>
								<el-radio v-model="state.day.cronEvery" label="9">
									<el-input-number v-model="state.day.cronDaysBeforeEomMinus" :min="1" :max="31"></el-input-number>
									{{ Language.Day.beforeEndMonth[0] }}
								</el-radio>
							</el-row> -->
								<el-row>
									<el-radio v-model="state.day.cronEvery" label="10"
										>{{ Language.Day.nearestWeekday[0] }}
										<el-input-number
											v-model="state.day.cronDaysNearestWeekday"
											:min="1"
											:max="31"
											style="width: 230px"
										></el-input-number>
										{{ Language.Day.nearestWeekday[1] }}
									</el-radio>
								</el-row>
								<el-row>
									<el-radio v-model="state.day.cronEvery" label="11"
										>{{ Language.Day.someWeekday[0] }}
										<el-input-number v-model="state.week.cronNthDayNth" :min="1" :max="5"></el-input-number>
										<el-select v-model="state.week.cronNthDayDay" style="width: 190px">
											<el-option v-for="(val, index) in 7" :key="index" :label="Language.Week[val - 1]" :value="val"></el-option>
										</el-select>
										{{ Language.Day.someWeekday[1] }}
									</el-radio>
								</el-row>
							</div>
						</el-tab-pane>
						<!-- 月 -->
						<el-tab-pane name="month">
							<template #label>
								<span><i class="el-icon-date"></i> {{ Language.Month.name }}</span>
							</template>
							<div class="tabBody myScroller" :style="{ 'max-height': maxHeight }">
								<el-row>
									<el-radio v-model="state.month.cronEvery" label="1">{{ Language.Month.every }}</el-radio>
								</el-row>
								<el-row>
									<el-radio class="long" v-model="state.month.cronEvery" label="3"
										>{{ Language.Month.specific }}
										<el-select multiple v-model="state.month.specificSpecific" @change="state.month.cronEvery = '3'">
											<el-option v-for="(val, index) in 12" :key="index" :label="val" :value="val"></el-option>
										</el-select>
									</el-radio>
								</el-row>
								<el-row>
									<el-radio v-model="state.month.cronEvery" label="2"
										>{{ Language.Month.interval[0] }}
										<el-input-number v-model="state.month.incrementIncrement" :min="0" :max="12"></el-input-number>
										{{ Language.Month.interval[1] }}
										<el-input-number
											v-model="state.month.incrementStart"
											:min="0"
											:max="12"
											style="width: 164px"
										></el-input-number>
									</el-radio>
								</el-row>
								<el-row>
									<el-radio v-model="state.month.cronEvery" label="4"
										>{{ Language.Month.cycle[0] }}
										<el-input-number v-model="state.month.rangeStart" :min="1" :max="12"></el-input-number>
										{{ Language.Month.cycle[1] }}
										<el-input-number v-model="state.month.rangeEnd" :min="1" :max="12" style="width: 226px"></el-input-number>
									</el-radio>
								</el-row>
							</div>
						</el-tab-pane>
						<!-- 年 -->
						<el-tab-pane v-if="false" name="year">
							<template #label>
								<span><i class="el-icon-date"></i> {{ Language.Year.name }}</span>
							</template>
							<div class="tabBody myScroller" :style="{ 'max-height': maxHeight }">
								<el-row>
									<el-radio v-model="state.year.cronEvery" label="1">{{ Language.Year.every }}</el-radio>
								</el-row>
								<el-row>
									<el-radio class="long" v-model="state.year.cronEvery" label="3"
										>{{ Language.Year.specific }}
										<el-select filterable multiple v-model="state.year.specificSpecific" @change="state.year.cronEvery = '3'">
											<el-option v-for="(val, index) in 100" :key="index" :label="2017 + val" :value="2017 + val"></el-option>
										</el-select>
									</el-radio>
								</el-row>
								<el-row>
									<el-radio v-model="state.year.cronEvery" label="2"
										>{{ Language.Year.interval[0] }}
										<el-input-number
											v-model="state.year.incrementIncrement"
											:min="1"
											:max="99"
											style="width: 164px"
										></el-input-number>
										{{ Language.Year.interval[1] }}
										<el-input-number v-model="state.year.incrementStart" :min="2018" :max="2118"></el-input-number>
									</el-radio>
								</el-row>
								<el-row>
									<el-radio v-model="state.year.cronEvery" label="4"
										>{{ Language.Year.cycle[0] }}
										<el-input-number v-model="state.year.rangeStart" :min="2018" :max="2118"></el-input-number>
										{{ Language.Year.cycle[1] }}
										<el-input-number v-model="state.year.rangeEnd" :min="2018" :max="2118" style="width: 226px"></el-input-number>
									</el-radio>
								</el-row>
							</div>
						</el-tab-pane>
					</el-tabs>
				</template>
				<template v-else>
					<div><el-input v-model="state.cron" placeholder="请输入cron表达式，如整点执行：0 0 * * * ?" /></div>
					<div class="pt-4 pl-2">
						<div class="flex items-center"><div class="font-bold">常用示例：</div></div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">30 * * * * ?</div>
							每30秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">30 10 * * * ?</div>
							每小时的10分30秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">30 10 1 * * ?</div>
							每天1点10分30秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">30 10 1 20 * ?</div>
							每月20号1点10分30秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">30 10 1 20 10 ? *</div>
							每年10月20号1点10分30秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">30 10 1 20 10 ? 2011</div>
							2011年10月20号1点10分30秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">30 10 1 ? 10 * 2011</div>
							2011年10月每天1点10分30秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">30 10 1 ? 10 SUN 2011</div>
							2011年10月每周日1点10分30秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">15,30,45 * * * * ?</div>
							每15秒，30秒，45秒时触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">15-45 * * * * ?</div>
							15到45秒内，每秒都触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">15/5 * * * * ?</div>
							每分钟的每15秒开始触发，每隔5秒触发一次
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">15-30/5 * * * * ?</div>
							每分钟的15秒到30秒之间开始触发，每隔5秒触发一次
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">0 0/3 * * * ?</div>
							每小时的第0分0秒开始，每三分钟触发一次
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">0 15 10 ? * MON-FRI</div>
							星期一到星期五的10点15分0秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">0 15 10 L * ?</div>
							每个月最后一天的10点15分0秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">0 15 10 LW * ?</div>
							每个月最后一个工作日的10点15分0秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">0 15 10 ? * 5L</div>
							每个月最后一个星期四的10点15分0秒触发任务
						</div>
						<div class="flex items-center">
							<div class="text-red-600 w-48">0 15 10 ? * 5#3</div>
							每个月第三周的星期四的10点15分0秒触发任务
						</div>
					</div>
				</template>
				<div v-if="state.configType == 'simple'" class="bottom flex justify-end mt-4">
					<div class="value" style="position: absolute; bottom: -46px; left: 15px">
						<span> cron预览: </span>
						<el-tag>
							{{ state.currCron }}
						</el-tag>
					</div>
				</div>
			</DialogBox>
		</div>
	</div>
</template>
<script lang="ts" setup>
import { formatCron } from "@/utils/format";
import DialogBox from "../DialogBox/index";
import Language from "./language/cn";
import { CronSimple } from "@/utils/constants";
import { reactive, computed, onMounted } from "vue";
const props = defineProps({
	modelValue: String,
	maxHeight: String || Number
});
const emit = defineEmits(["update:modelValue"]);
const state: any = reactive({
	advanced: false,
	configType: "simple",
	currTab: "hour",
	cron: "",
	second: {
		cronEvery: "3",
		incrementStart: 0,
		incrementIncrement: 15,
		rangeStart: 0,
		rangeEnd: 0,
		specificSpecific: [0]
	},
	minute: {
		cronEvery: "3",
		incrementStart: 0,
		incrementIncrement: 10,
		rangeStart: 0,
		rangeEnd: 0,
		specificSpecific: [0]
	},
	hour: {
		cronEvery: "1",
		incrementStart: 0,
		incrementIncrement: 1,
		rangeStart: 0,
		rangeEnd: 0,
		specificSpecific: []
	},
	day: {
		cronEvery: "1",
		incrementStart: 1,
		incrementIncrement: 1,
		rangeStart: 0,
		rangeEnd: 0,
		specificSpecific: [],
		cronLastSpecificDomDay: 1,
		cronDaysBeforeEomMinus: 0,
		cronDaysNearestWeekday: 0
	},
	week: {
		cronEvery: "1",
		incrementStart: 1,
		incrementIncrement: 1,
		specificSpecific: [],
		cronNthDayDay: 1,
		cronNthDayNth: 1
	},
	month: {
		cronEvery: "1",
		incrementStart: 3,
		incrementIncrement: 5,
		rangeStart: 0,
		rangeEnd: 0,
		specificSpecific: []
	},
	year: {
		cronEvery: "3",
		incrementStart: 2017,
		incrementIncrement: 1,
		rangeStart: 0,
		rangeEnd: 0,
		specificSpecific: []
	},
	output: {
		second: "",
		minute: "",
		hour: "",
		day: "",
		month: "",
		Week: "",
		year: ""
	},
	text: Language as any,
	secondsText: computed(() => {
		return getTextValue(state.second);
	}),
	minutesText: computed(() => {
		return getTextValue(state.minute);
	}),
	hoursText: computed(() => {
		return getTextValue(state.hour);
	}),
	daysText: computed(() => {
		let days = "";
		let cronEvery = state.day.cronEvery;
		switch (cronEvery.toString()) {
			case "1":
				break;
			case "2":
			case "4":
			case "11":
				days = "?";
				break;
			case "3":
				days = state.day.incrementStart + "/" + state.day.incrementIncrement;
				break;
			case "5":
				state.day.specificSpecific.map((val: any) => {
					days += val + ",";
				});
				days = days.slice(0, -1);
				break;
			case "6":
				days = "L";
				break;
			case "7":
				days = "LW";
				break;
			case "8":
				days = state.day.cronLastSpecificDomDay + "L";
				break;
			case "9":
				days = "L-" + state.day.cronDaysBeforeEomMinus;
				break;
			case "10":
				days = state.day.cronDaysNearestWeekday + "W";
				break;
		}
		return days;
	}),
	weeksText: computed(() => {
		let weeks = "";
		let cronEvery = state.day.cronEvery;
		switch (cronEvery.toString()) {
			case "1":
			case "3":
			case "5":
				weeks = "?";
				break;
			case "2":
				weeks = state.week.incrementStart + "/" + state.week.incrementIncrement;
				break;
			case "4":
				state.week.specificSpecific.map((val: any) => {
					weeks += val + ",";
				});
				weeks = weeks.slice(0, -1);
				break;
			case "6":
			case "7":
			case "8":
			case "9":
			case "10":
				weeks = "?";
				break;
			case "11":
				weeks = state.week.cronNthDayDay + "#" + state.week.cronNthDayNth;
				break;
		}
		return weeks;
	}),
	monthsText: computed(() => {
		return getTextValue(state.month);
	}),
	yearsText: computed(() => {
		return getTextValue(state.year);
	}),
	currCron: computed(() => {
		//没有输入年份，则去掉年份
		let val = `${state.secondsText || "*"} ${state.minutesText || "*"} ${state.hoursText || "*"} ${state.daysText || "*"} ${
			state.monthsText || "*"
		} ${state.weeksText || "?"} ${!state.yearsText || state.yearsText == "*" ? "" : state.yearsText}`
			.replaceAll("null", "*")
			.replaceAll("  ", "0");
		return val;
	})
});
const getTextValue = (target: {
	cronEvery: string;
	incrementStart: number;
	incrementIncrement: number;
	specificSpecific: string[];
	rangeStart: string;
	rangeEnd: string;
}) => {
	let text = "";
	let cronEvery = target.cronEvery;
	switch (cronEvery.toString()) {
		case "1":
			text = "*";
			break;
		case "2":
			text = target.incrementStart + "/" + target.incrementIncrement;
			break;
		case "3":
			target.specificSpecific.map((val: any) => {
				text += val + ",";
			});
			text = text.slice(0, -1);
			break;
		case "4":
			text = target.rangeStart + "-" + target.rangeEnd;
			break;
	}
	return text;
};
onMounted(() => {
	setTimeout(() => {
		state.cron = props.modelValue;
	}, 500);
});
// const selectBlue = (e: Event) => {
// 	state.cron = (e.target as HTMLInputElement).value;
// 	selectSimple();
// };
const selectSimple = () => {
	emit("update:modelValue", state.cron);
};
const change = () => {
	state.advanced = false;
	if (state.configType == "simple") {
		//可视化配置
		state.cron = state.currCron;
		emit("update:modelValue", state.currCron);
	} else {
		//手动输入
		emit("update:modelValue", state.cron);
	}
};
const reset = (data: any) => {
	for (let i in data) {
		if (data[i] instanceof Object) {
			reset(data[i]);
		} else {
			switch (typeof data[i]) {
				case "object":
					data[i] = [];
					break;
				case "string":
					data[i] = "";
					break;
			}
		}
	}
};
defineExpose({ reset });
</script>
<style lang="scss">
@import "./index.scss";
</style>
